﻿using System;
using System.Threading;
using NUnit.Framework;
using NUnit.Framework.SyntaxHelpers;
using SimpleServiceBus.Bus;
using SimpleServiceBus.Bus.Transport;
using SimpleServiceBus.Tests.Stubs;

namespace SimpleServiceBus.Tests.Bus.Transport
{
    [TestFixture]
    public class BaseTransportTestFixture
    {
        [Test]
        public void Can_Receive_Message_And_Fire_Correct_Events()
        {
            var transport = new TestTransport();
            transport.Start(true);
            try
            {
                var message = new MessageEnvelope { Body = "Hello" };

                using (var recorder = new EventRecorder(transport))
                {
                    transport.Receive(message);
                    transport.NextMessage.WaitOne(TimeSpan.FromSeconds(1), false);

                    Assert.That(recorder.EventCount, Is.EqualTo(3));
                    Assert.That(recorder.EventHistory[0].EventName, Is.EqualTo("MessageProcessingStarted"));
                    Assert.That(recorder.EventHistory[1].EventName, Is.EqualTo("MessageReceived"));
                    Assert.That(recorder.EventHistory[2].EventName, Is.EqualTo("MessageProcessingFinished"));

                    Assert.That(((MessageReceivedEventArgs)recorder.EventHistory[1].Args).MessageEnvelope,
                                Is.SameAs(message));
                }
            }
            finally
            {
                transport.Stop();
            }
        }

        [Test]
        public void Can_Receive_Null_Message_Gracefully()
        {
            var transport = new TestTransport();
            transport.Start(true);
            try
            {
                using (var recorder = new EventRecorder(transport))
                {
                    transport.Receive(null);
                    transport.NextMessage.WaitOne(TimeSpan.FromSeconds(1), false);

                    Assert.That(recorder.EventCount, Is.EqualTo(2));
                    Assert.That(recorder.EventHistory[0].EventName, Is.EqualTo("MessageProcessingStarted"));
                    Assert.That(recorder.EventHistory[1].EventName, Is.EqualTo("MessageProcessingFinished"));
                }
            }
            finally
            {
                transport.Stop();
            }
        }

        [Test]
        [Ignore(
            "This test relies too much on timing - it passes usually, but if the thread sleeps aren't set at a high value, it doesn't always pass, and then it takes too long to run."
            )]
        public void Change_Number_Of_Worker_Threads_Test()
        {
            var transport = new TestTransport {NumberOfWorkerThreads = 3};

            transport.Start();

            Assert.That(transport.NumberOfWorkerThreads, Is.EqualTo(3));
            transport.ChangeNumberOfWorkerThreads(2);
            Thread.Sleep(50);

            Assert.That(transport.NumberOfWorkerThreads, Is.EqualTo(2));
            transport.ChangeNumberOfWorkerThreads(1);
            Thread.Sleep(25);

            Assert.That(transport.NumberOfWorkerThreads, Is.EqualTo(1));
            transport.ChangeNumberOfWorkerThreads(2);
            Thread.Sleep(25);

            Assert.That(transport.NumberOfWorkerThreads, Is.EqualTo(2));
            transport.ChangeNumberOfWorkerThreads(3);
            Thread.Sleep(25);

            Assert.That(transport.NumberOfWorkerThreads, Is.EqualTo(3));

            transport.Stop();
            Thread.Sleep(25);

            Assert.That(transport.NumberOfWorkerThreads, Is.EqualTo(0));
        }

        [Test]
        public void Receive_Message_Later_Test()
        {
            var transport = new TestTransport();
            transport.Start(true);
            try
            {
                var message = new MessageEnvelope { Body = "Hello" };

                using (var recorder = new EventRecorder(transport))
                {
                    transport.ReceiveMessageLater(message);
                    transport.NextMessage.WaitOne(TimeSpan.FromSeconds(1), false);

                    Assert.That(recorder.EventCount, Is.EqualTo(3));
                    Assert.That(recorder.EventCountFor("MessageReceived"), Is.EqualTo(1));
                    Assert.That(((MessageReceivedEventArgs)recorder.EventHistory[1].Args).MessageEnvelope,
                                Is.SameAs(message));
                }
            }
            finally
            {
                transport.Stop();
            }
        }

        [Test]
        public void Start_Stop_Test()
        {
            var transport = new TestTransport();

            transport.Start();
            Assert.IsTrue(transport.IsRunning);
            transport.Stop();
            Assert.IsFalse(transport.IsRunning);
        }
    }
}